/* 
 * This program is free software; you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; either version 3 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
 * for more details.
 * 
 * You should have received a copy of the GNU General Public License along 
 * with this program; if not, write to the Free Software Foundation, Inc., 
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include <QFileDialog>
#include <QMessageBox>
#include <QInputDialog>
#include <QFile>
#include "chanlisteditor.h"
#include "log.h"
#include "boardparsers/parserfactory.h"
#include "newchandialog.h"
#include "chanagents/chanagent.h"
#include "chanagents/standardagentfactory.h"

PropertyHub::PropertyHub()
{
}

PropertyHub::~PropertyHub()
{
}

void PropertyHub::setProperty(const QString& key, const QVariant& value)
{
	m_values[key] = value;
}

QVariant PropertyHub::property(const QString& key)
{
	return m_values.value(key);
}

QStringList PropertyHub::allKeys()
{
	return m_values.keys();
}

ChanListItem::ChanListItem(const QString& name, QTreeWidget* parent) : QTreeWidgetItem(parent, ChanItem), 
	PropertyHub()
{
	setText(2, name);
}

ChanListItem::ChanListItem(const QString& name, QTreeWidgetItem* parent) : QTreeWidgetItem(parent, BoardItem),
	PropertyHub()
{
	setText(2, name);
}

AgentSettingsItem::AgentSettingsItem(const QString& name, QTreeWidgetItem* parent) : QTreeWidgetItem(parent, AgentSettings)
{
	Q_ASSERT(parent->type() == ChanListItem::ChanItem);
	setText(2, name);
}

ChanListEditor::ChanListEditor(QWidget* parent) : QDialog(parent),
	m_ui(new Ui::ChanListEditor)
{
	m_ui->setupUi(this);
	m_agentFactory = new Wishmaster::StandardAgentFactory();
}

ChanListEditor::~ChanListEditor()
{
	delete m_agentFactory;
}

bool ChanListEditor::loadChanlist(const QString& filename)
{
	QFile f(filename);
	if(!f.open(QIODevice::ReadOnly))
	{
		log(llError, "Unable to load chanlist from file: %s", qPrintable(filename));
		return false;
	}
	m_filename = filename;
	QDomDocument m_document;
	m_document.setContent(f.readAll());
	QDomNodeList list = m_document.childNodes().at(1).childNodes();
	for(unsigned int i = 0; i < list.length(); i++)
	{
		QDomNode node = list.at(i);
		if(node.nodeName() == "chan")
		{
			ChanListItem* chanitem = new ChanListItem(node.attributes().namedItem("name").toAttr().value(), m_ui->tw_chanlist);
			chanitem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
			chanitem->setCheckState(0, Qt::Checked);
			QDomNodeList boards = node.childNodes();
			for(unsigned int j = 0; j < boards.length(); j++)
			{
				QDomNode board = boards.at(j);
				PropertyHub* item = 0;
				QTreeWidgetItem* childitem = 0;
				if(board.nodeName() == "board")
				{
					ChanListItem* theitem;
					theitem = addBoardItem(chanitem, board.attributes().namedItem("link").toAttr().value(),
							board.attributes().namedItem("alias").toAttr().value());
					item = theitem;
					childitem = theitem;
				}
				else if(board.nodeName() == "agentsettings")
				{
					item = new AgentSettingsItem(tr("Agent Settings"), chanitem);
					childitem = dynamic_cast<QTreeWidgetItem*>(item);
				}
				else
				{
					log(llDebug, "Unknown nodename: %s", qPrintable(board.nodeName()));
				}
				if(item)
				{
					QDomNamedNodeMap map = board.attributes();
					for(int k = 0; k < map.size(); k++)
					{
						QDomAttr n = map.item(k).toAttr();
						if(n.name() != "disabled")
							item->setProperty(n.name().toUtf8().data(), n.value());
						else
						{
							if(n.value() == "true")
								childitem->setCheckState(1, Qt::Unchecked);
							else
								childitem->setCheckState(1, Qt::Checked);
						}
					}
				}
			}
			QDomNamedNodeMap map = node.attributes();
			for(int k = 0; k < map.size(); k++)
			{
				QDomAttr n = map.item(k).toAttr();
				if(n.name() != "disabled")
					chanitem->setProperty(n.name().toUtf8().data(), n.value());
				else
				{
					if(n.value() == "true")
						chanitem->setCheckState(0, Qt::Unchecked);
				}
			}
		}
	}
	updateColumnSizes();
	return true;
}

void ChanListEditor::updateColumnSizes()
{
	m_ui->tw_chanlist->resizeColumnToContents(0);
	m_ui->tw_chanlist->resizeColumnToContents(1);
}

bool ChanListEditor::saveChanlist(const QString& filename)
{
	// TODO Rewrite it using QDomDocument
	QFile file(filename);
	if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
		return false;
	QString xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
	xml += "<chans>\n";

	for(int i = 0; i < m_ui->tw_chanlist->topLevelItemCount(); i++)
	{
		xml += "<chan ";
		QTreeWidgetItem* item = m_ui->tw_chanlist->topLevelItem(i);
		PropertyHub* chanhub = dynamic_cast<PropertyHub*>(item);
		Q_ASSERT(chanhub);
		QStringList chankeys = chanhub->allKeys();
		foreach(QString chankey, chankeys)
		{
			QString prop = chanhub->property(chankey).toString();
			prop.replace("&", "&amp;");
			xml += QString("%1=\"%2\" ").arg(chankey).arg(prop); // TODO convert to xml entities
		}
		if(item->checkState(0) == Qt::Unchecked)
			xml += "disabled=\"true\"";
		xml += ">\n";
		for(int j = 0; j < item->childCount(); j++)
		{
			QTreeWidgetItem* childitem = item->child(j);
			PropertyHub* childhub = dynamic_cast<PropertyHub*>(childitem);
			Q_ASSERT(childhub);
			if(childitem->type() == ChanListItem::BoardItem)
			{
				xml += "\t<board ";
				if(childitem->checkState(1) == Qt::Unchecked)
					xml += "disabled=\"true\" ";
			}
			else if(childitem->type() == AgentSettingsItem::AgentSettings)
			{
				xml += "\t<agentsettings ";
			}
			QStringList childkeys = childhub->allKeys();
			foreach(QString childkey, childkeys)
			{
				QString prop = childhub->property(childkey).toString();
				prop.replace("&", "&amp;");
				xml += QString("%1=\"%2\" ").arg(childkey).arg(prop); // TODO convert to xml entities
			}
			xml += "/>\n";
		}
		xml += "</chan>\n";
	}
	xml += "</chans>\n";
	file.write(xml.toUtf8());
	return true;
}

void ChanListEditor::itemActivated(QTreeWidgetItem* item, int column)
{
	PropertyHub* hub = dynamic_cast<PropertyHub*>(item);
	Q_ASSERT(hub);
	m_ui->tw_props->clear();
	QStringList keys = hub->allKeys();
	m_ui->tw_props->setRowCount(keys.size());
	int row = 0;
	foreach(QString key, keys)
	{
		QTableWidgetItem* keyitem = new QTableWidgetItem(key);
		QTableWidgetItem* valitem = new QTableWidgetItem(hub->property(key).toString());
		keyitem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
		m_ui->tw_props->setItem(row, 0, keyitem);
		m_ui->tw_props->setItem(row, 1, valitem);
		row++;
	}
	m_ui->tw_props->resizeColumnsToContents();
	m_ui->tw_props->resizeRowsToContents();
}

void ChanListEditor::itemSelectionChanged()
{
	QList<QTreeWidgetItem*> items = m_ui->tw_chanlist->selectedItems();
	if(items.size() == 0)
	{
		if(m_ui->b_addBoard->isEnabled())
			m_ui->b_addBoard->setEnabled(false);
	}
	else
	{
		if(!m_ui->b_addBoard->isEnabled())
		{
			m_ui->b_addBoard->setEnabled(true);
		}
	}

}

void ChanListEditor::propertyChanged(QTableWidgetItem* item)
{
	QTreeWidgetItem* parent = m_ui->tw_chanlist->currentItem();
	PropertyHub* hub = dynamic_cast<PropertyHub*>(parent);
	Q_ASSERT(hub);
	if(item->column() == 1)
	{
		QTableWidgetItem* keyitem = item->tableWidget()->item(item->row(), 0);
		hub->setProperty(keyitem->text(), item->text());
		m_ui->tw_props->resizeColumnsToContents();
	}
}

void ChanListEditor::addProperty()
{
	QString key = QInputDialog::getText(this, QString::null, tr("Enter new property name"));
	if(!key.isNull())
	{
		int lastrow = m_ui->tw_props->rowCount();
		m_ui->tw_props->setRowCount(lastrow + 1);
		QTableWidgetItem* keyitem = new QTableWidgetItem(key);
		QTableWidgetItem* valitem = new QTableWidgetItem("");
		keyitem->setFlags(Qt::ItemIsEnabled);
		m_ui->tw_props->setItem(lastrow, 0, keyitem);
		m_ui->tw_props->setItem(lastrow, 1, valitem);
	}
	m_ui->tw_props->resizeColumnsToContents();
}

void ChanListEditor::removeProperty()
{
	QList<QTableWidgetItem*> items = m_ui->tw_props->selectedItems();
	foreach(QTableWidgetItem* item, items)
	{
		int row = item->row();
		m_ui->tw_props->removeRow(row);
	}
	m_ui->tw_props->resizeColumnsToContents();
}

void ChanListEditor::saveAs()
{
	QString filename = QFileDialog::getSaveFileName(this, tr("Save settings as:"), QString(), tr("Chanlist (*.xml)"));
	if(!filename.isNull())
	{
		if(!filename.endsWith(".xml", Qt::CaseInsensitive))
		{
			filename += ".xml";
		}
		saveChanlist(filename);
	}
}

void ChanListEditor::accept()
{
	if(QMessageBox::question(this, QString(), tr("Are you sure?"), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes)
		return;
	saveChanlist(m_filename);
	QDialog::accept();
}

void ChanListEditor::reject()
{
	QDialog::reject();
}

void ChanListEditor::clicked(QAbstractButton* button)
{
	if(m_ui->buttonBox->standardButton(button) == QDialogButtonBox::Save)
		accept();
	else if(m_ui->buttonBox->standardButton(button) == QDialogButtonBox::Discard)
		reject();
}

void ChanListEditor::addChan()
{
	NewChanDialog dlg(m_agentFactory->agentList(), Wishmaster::ParserFactory::parserList(), this);
	if(dlg.exec() == QDialog::Rejected)
		return;
	ChanListItem* chanitem = new ChanListItem(dlg.chanName(), m_ui->tw_chanlist); 
	PropertyHub* newchan = chanitem;
	newchan->setProperty("name", dlg.chanName());
	newchan->setProperty("url", dlg.url());
	newchan->setProperty("agent", dlg.agent());
	newchan->setProperty("parser", dlg.parser());
	QTreeWidgetItem* item = new AgentSettingsItem(tr("Agent Settings"), dynamic_cast<QTreeWidgetItem*>(newchan));
	item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable);
	item->setCheckState(0, Qt::Checked);
	m_ui->tw_chanlist->reset();
}

void ChanListEditor::addBoard()
{
	QList<QTreeWidgetItem*> items = m_ui->tw_chanlist->selectedItems();
	if(items.size() == 0)
		return;
	QTreeWidgetItem* selected = items.at(0);
	QString link = QInputDialog::getText(this, QString::null, tr("Enter link to the new board (e.g. /b/, /d/)"));
	if(!link.isNull())
	{
		if(!link.endsWith('/'))
			link.append('/');
		if(!link.startsWith('/'))
			link.prepend('/');
		PropertyHub* item = 0;
		//QTreeWidgetItem* it = 0;
		if(selected->type() == ChanListItem::ChanItem)
		{
			ChanListItem* newitem = new ChanListItem(link, selected);
			item = newitem;
			newitem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable);
			newitem->setCheckState(0, Qt::Checked);
		}
		else // It's either AgentSettingsItem or BoardItem
		{
			Q_ASSERT(selected->parent() != 0);
			ChanListItem* newitem = new ChanListItem(link, selected->parent());
			item = newitem;
			newitem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable);
			newitem->setCheckState(1, Qt::Checked);
		}
		Q_ASSERT(item);
		item->setProperty("alias", link);
		item->setProperty("link", link);
	}
}

void ChanListEditor::removeChan()
{
	QList<QTreeWidgetItem*> items = m_ui->tw_chanlist->selectedItems();
	foreach(QTreeWidgetItem* item, items)
	{
		delete item;
	}
}

ChanListItem* ChanListEditor::addBoardItem(ChanListItem* parent, const QString& name, const QString& alias)
{
	ChanListItem* item = new ChanListItem(alias, parent);
	item->setProperty("link", name);
	item->setProperty("alias", alias);
	item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
	item->setCheckState(1, Qt::Checked);
	return item;
}

void ChanListEditor::addAgentItem(ChanListItem* parent, const QMap<QString, QString> settings)
{
	AgentSettingsItem* item = 0;
	for(int i = 0; i < parent->childCount(); i++)
	{
		if(parent->child(i)->type() == AgentSettingsItem::AgentSettings)
		{
			item = static_cast<AgentSettingsItem*>(parent->child(i));
			break;
		}
	}
	if(!item)
		item = new AgentSettingsItem(tr("Agent settings"), parent);
	QMapIterator<QString, QString> it(settings);
	while(it.hasNext())
	{
		it.next();
		item->setProperty(it.key(), it.value());
	}
}

